/*
 * Copyright (C) 2018-2020 Alibaba Group Holding Limited
 */

#include <string.h>
// #include <stdlib.h>
#include <aos/debug.h>
#include <aos/kernel.h>
#include <player.h>
#include <string.h>
#include <mvoice_alg.h>
#include <avformat/avparser_all.h>
#include <stream/stream_all.h>
#include <avformat/avformat_all.h>
#include <avcodec/avcodec_all.h>
#include "local_audio.h"
#include "app_sys.h"

#define TAG                    "laudio"

#define EVT_PLY_FINISH      1

static aos_event_t evt_player;
static player_t* player_hdl;
static int8_t recording_paused = 0;
aos_mutex_t laudio_lock;
static int8_t audio_playing = 0;

static int check_set_playing()
{
    int ret = 0;
    aos_mutex_lock(&laudio_lock, AOS_WAIT_FOREVER);
    if (!audio_playing) {
        audio_playing = 1;
        ret = 1;
    }

    aos_mutex_unlock(&laudio_lock);

    return ret;
}

static int set_unplaying()
{
    aos_mutex_lock(&laudio_lock, AOS_WAIT_FOREVER);
    audio_playing = 0;
    aos_mutex_unlock(&laudio_lock);
}

static int audio_play(char *url, int async) 
{
    aos_check_return_einval(url);

    LOGD(TAG, "play local audio %s", url);
    int ret;
    unsigned int flags = 0;

    if (check_set_playing()) {
        aos_event_set(&evt_player, 0, AOS_EVENT_AND);

        if (!recording_paused) {
            recording_paused = 1;
            mvoice_process_pause();
        }

        ret = player_play(player_hdl, url, 0);

        if (ret == 0 && !async) {
            aos_event_get(&evt_player, EVT_PLY_FINISH, AOS_EVENT_OR_CLEAR, &flags, AOS_WAIT_FOREVER);
        } else if (ret != 0) {
            LOGE(TAG, "player play error %d", ret);

            /* FIXME: reboot when memory not enough */
            int total = 0,used = 0,mfree = 0,peak = 0;
            aos_get_mminfo(&total, &used, &mfree, &peak);
            if (mfree < 10000) {
                LOGE(TAG, "not enough memory: %d B", mfree);
                app_sys_set_boot_reason(BOOT_REASON_SILENT_RESET);
                aos_reboot();
            }

            // if (recording_paused) {
            //     recording_paused = 0;
            //     mvoice_process_resume();
            // }
            // set_unplaying();
            return -1;
        }

        return 0;
    }

    LOGW(TAG, "failed to get play lock");
    return -1;
}

static void _player_event(player_t *player, uint8_t type, const void *data, uint32_t len)
{
    int rc;
    LOGD(TAG, "=====%s, %d, type = %d", __FUNCTION__, __LINE__, type);

    switch (type) {
    case PLAYER_EVENT_ERROR:
        rc = player_stop(player);
        aos_event_set(&evt_player, EVT_PLY_FINISH, AOS_EVENT_OR);
        break;

    case PLAYER_EVENT_START: {
        media_info_t minfo;
        memset(&minfo, 0, sizeof(media_info_t));
        rc = player_get_media_info(player, &minfo);
        LOGD(TAG, "=====rc = %d, duration = %llums, bps = %llu, size = %u", rc, minfo.duration, minfo.bps, minfo.size);
        break;
    }

    case PLAYER_EVENT_FINISH:
        player_stop(player);
        aos_event_set(&evt_player, EVT_PLY_FINISH, AOS_EVENT_OR);
        break;

    default:
        break;
    }

    if (type == PLAYER_EVENT_FINISH || type == PLAYER_EVENT_ERROR) {
        if (recording_paused) {
            recording_paused = 0;
            mvoice_process_resume();
        }

        set_unplaying();
    }
}

int local_audio_play(const char *content, int async)
{
    aos_check_return_einval(content);
    char url[128] = {0};
    int ret;

    for (int i = 0; i < g_audio_name_map_len; i++) {
        if (strcmp(g_audio_name_map[i].content, content) == 0) {
            snprintf(url, 127, "mem://addr=%u&size=%u", g_audio_name_map[i].audio, g_audio_name_map[i].audio_len);
            
            return audio_play(url, async);
        }
    }

    LOGW(TAG, "no audio found %s", content);
    return -1;
}

int local_audio_vol_get()
{
    uint8_t vol;

    if (player_get_vol(player_hdl, &vol) == 0) {
        return vol;
    }

    return -1;
}

int local_audio_vol_set(uint8_t vol)
{
    return player_set_vol(player_hdl, vol);
}

int player_init()
{
    static int inited = 0;

    if (!inited) {
        // resample_register();
        // eqx_register();
        // aefx_register();
        // atempo_register();
        avparser_register_all();

        stream_register_all();
        demux_register_all();
        ad_register_all();
        // ao_register_all();
        ao_register_user();

        inited = 1;
    }

    return inited ? 0 : -1;
}

int local_audio_init()
{
    ply_conf_t ply_cnf;

    aos_event_new(&evt_player, 0);
    aos_mutex_new(&laudio_lock);

    player_init();
    player_conf_init(&ply_cnf);
    //ply_cnf.rcv_timeout = 0;
    //ply_cnf.cache_size  = 800*1024;
    // ply_cnf.atempo_play_en = 1;
    ply_cnf.ao_name      = "w800";
    ply_cnf.vol_en      = 1;
    ply_cnf.vol_index   = 160; // 0~255
    // ply_cnf.get_dec_cb  = _get_decrypt;
    ply_cnf.event_cb    = _player_event;
    // ply_cnf.resample_rate = resample_rate;
    /* config the aef param */
    //ply_cnf.aef_conf      = sona_aef_config;
    //ply_cnf.aef_conf_size = sona_aef_config_len;

    player_hdl = player_new(&ply_cnf);
}

#if defined(CONFIG_IR_DEMO) || CONFIG_IR_DEMO
int local_audio_array_play(int i, int async)
{
    if (i < 0 || i > audio_array_map_len) {
        LOGE(TAG, "audio play index error %d", i);
        return -1;
    }

    char url[128] = {0};
    int index = audio_array_map[i];

    if (index < 0) {
        LOGE(TAG, "invalid audio index %d", i);
        return -1;
    }

    LOGD(TAG, "audio array index %d -> %d", i, index);
    snprintf(url, 127, "mem://addr=%u&size=%u", g_audio_name_array[index].audio, g_audio_name_array[index].audio_len);
    return audio_play(url, async);     
}
#endif
